﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SharpMUD.Framework.Services;
using SharpMUD.Framework.Services.Security;
using SharpMUD.Framework.Security;

namespace SharpMUD.Framework.Workflow.SessionState
{
    public class SessionStateContainer<T>
        : ISessionStateContainer<T>
        where T : IUserSession
    {
        private List<ISessionState<T>> _StateList;

        public SessionStateContainer(string id, IEnumerable<ISessionState<T>> sessionStates)
        {
            if (id == null) throw new ArgumentNullException("id");
            if (sessionStates == null) throw new ArgumentNullException("sessionStates");
            
            this.ID = id;
            this._StateList = new List<ISessionState<T>>(sessionStates);
        }
        public SessionStateContainer(string id)
            : this(id,new ISessionState<T>[] {})
        { }
        public SessionStateContainer(IEnumerable<ISessionState<T>> sessionStates)
            : this(String.Empty,sessionStates)
        { }

        #region ISessionStateContainer<T> Members

        public ISessionState<T> Peek()
        {
            if (_StateList.Count > 0)
                return _StateList[0];
            else
                return null;
        }

        public ISessionState<T> Pop()
        {
            if (_StateList.Count > 0)
            {
                ISessionState<T> result = this._StateList[0];
                this._StateList.RemoveAt(0);
                return result;
            }
            else
            {
                return null;
            }
        }

        public void Push(ISessionState<T> sessionState)
        {
            if (sessionState == null)
                throw new ArgumentNullException("sessionState");
            lock (_StateList)
            {
                _StateList.Insert(0, sessionState);
            }
        }

        public void Enqueue(ISessionState<T> sessionState)
        {
            if (sessionState == null)
                throw new ArgumentNullException("sessionState");
            lock (_StateList)
            {
                _StateList.Add(sessionState);
            }
        }

        #endregion

        #region ISessionState<T> Members

        public string ID
        {
            get;
            private set;
        }

        public SessionActionResult PerformAction(T session)
        {
            lock (this._StateList)
            {
                ISessionState<T> activeSessionState = this.Peek();
                if (activeSessionState == null)
                    return SessionActionResult.Complete;

                SessionActionResult actionResult = activeSessionState.PerformAction(session);

                if (actionResult == SessionActionResult.Complete)
                {
                    this._StateList.Remove(activeSessionState);
                    if (this._StateList.Count > 0)
                    {
                        return SessionActionResult.Incomplete;
                    }
                    else
                        return SessionActionResult.Complete;
                }
                else if (actionResult == SessionActionResult.Incomplete)
                {
                    return SessionActionResult.Incomplete;
                }
                else
                {
                    throw new InvalidOperationException();
                }
            }
        }

        #endregion

        #region IEnumerable<ISessionState<T>> Members

        public IEnumerator<ISessionState<T>> GetEnumerator()
        {
            return _StateList.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _StateList.GetEnumerator();
        }

        #endregion

        #region ISessionStateContainer<T> Members


        public ISessionState<T> GetActiveSessionState()
        {
            if (_StateList.Count > 0)
            {
                ISessionState<T> returnValue = null;
                ISessionState<T> topActiveState = _StateList[0];
                if (topActiveState is ISessionStateContainer<T>)
                {
                    returnValue = ((ISessionStateContainer<T>)topActiveState).GetActiveSessionState();
                }
                else
                {
                    returnValue = topActiveState;
                }
                return returnValue;
            }
            else
            {
                return null;
            }
        }

        public IEnumerable<ISessionState<T>> GetPathToActiveSessionState()
        {
            if (this._StateList.Count <= 0)
                return new ISessionState<T>[] {};
            else
            {
                List<ISessionState<T>> resultList = new List<ISessionState<T>>();
                resultList.Add(this);
                if (this._StateList[0] is ISessionStateContainer<T>)
                {
                    resultList.AddRange((this._StateList[0] as ISessionStateContainer<T>).GetPathToActiveSessionState());
                }
                else
                {
                    resultList.Add(this._StateList[0]);
                }
                return resultList;
            }
        }

        public ISessionStateContainer<T> GetContainerOfActiveSessionState()
        {
            if (this._StateList.Count <= 0)
                return null;
            else
            {
                if (this._StateList[0] is ISessionStateContainer<T>)
                    return (this._StateList[0] as ISessionStateContainer<T>).GetContainerOfActiveSessionState();
                else
                    return this;
            }
        }

        #endregion
    }
}
